package judesart.app.repository;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import judesart.app.domain.Address;
import judesart.app.domain.Artwork;
import judesart.app.domain.Exhibition;
import judesart.app.domain.ExhibitionArtwork;
import judesart.app.domain.ExhibitionPhoto;
import judesart.app.domain.ExhibitionVideo;
import judesart.app.domain.Image;
import judesart.app.shared.ValidationException;
import judesart.app.validation.AppValidator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.google.appengine.api.datastore.Text;

@Repository
public class ExhibitionDAOImpl implements ExhibitionDAO {
    private final static Log LOGGER = LogFactory.getLog(ExhibitionDAOImpl.class);

    @PersistenceContext
    EntityManager entityManager;

    @Inject
    private AppValidator validator;

    @Inject
    private ImageDAO imageDAO;

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Exhibition addArtworkToExhibition(Exhibition exhibition,
            Artwork artwork) {
        exhibition = entityManager.merge(exhibition);
        exhibition.addArtwork(artwork);
        entityManager.flush();
        return exhibition;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Exhibition addPhotoToExhibition(Exhibition exhibition,
            String fileName, String blobKey) {
        Image image = new Image();
        image.setBlobKey(blobKey);
        image.setName(fileName);
        image = imageDAO.createImage(image);
        exhibition = entityManager.merge(exhibition);
        exhibition.addPhoto(image);
        entityManager.flush();
        return exhibition;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Exhibition addVideoToExhibition(Exhibition exhibition, String videoId) {
        exhibition = entityManager.merge(exhibition);
        ExhibitionVideo video = exhibition.addVideo(videoId);
        // entityManager.persist(video);
        entityManager.flush();
        return exhibition;
    }

    @Override
    public int countExhibitions(Long artistId) {
        return (Integer) entityManager.createNamedQuery(
                "Exhibition.countByArtistId").setParameter("artistId", artistId).getSingleResult();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Exhibition createExhibition(Exhibition exhibition)
            throws ValidationException {
        validator.validate(exhibition);
        entityManager.persist(exhibition);
        entityManager.flush();
        return exhibition;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Exhibition deleteArtworkFromExhibition(Exhibition exhibition,
            Artwork artwork) {
        exhibition = entityManager.merge(exhibition);
        exhibition.removeArtwork(artwork);
        entityManager.flush();
        return exhibition;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteExhibition(Long exhibitionId) {
        Exhibition exhibition = entityManager.find(Exhibition.class,
                exhibitionId);
        entityManager.remove(exhibition);
        entityManager.flush();
        if (exhibition.getPhotos() != null) {
            for (ExhibitionPhoto photo : exhibition.getPhotos()) {
                imageDAO.deleteImage(photo.getImageId());
            }
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Exhibition deletePhotoFromExhibition(Exhibition exhibition,
            Long photoId) {
        Image image = imageDAO.deleteImage(photoId);
        if (image != null) {
            exhibition = entityManager.merge(exhibition);
            exhibition.removePhoto(image);
            entityManager.flush();
        }
        return exhibition;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Exhibition findExhibitionById(Long exhibitionId) {
        Exhibition exhibition = entityManager.find(Exhibition.class,
                exhibitionId);
        if (exhibition != null)
            loadExhibitionDependencies(exhibition);
        return exhibition;
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Long> findExhibitionIdsByArtworkId(Long artworkId) {
        List<Exhibition> exhibitions = entityManager.createNamedQuery(
                "ExhibitionArtwork.findExhibitionsByArtworkId").setParameter(
                "artworkId", artworkId).getResultList();
        List<Long> result = new ArrayList<Long>();
        for (Exhibition exhibition : exhibitions) {
            result.add(exhibition.getId());
        }
        return result;
    }

    @Override
    public String findExhibitionPhotoKeyByImageId(Long imageId) {
        return (String) entityManager.createNamedQuery(
                "ExhibitionPhoto.findKeyByImageId").setParameter("imageId",
                imageId).getSingleResult();
    }

    @SuppressWarnings("unchecked")
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public List<Exhibition> findExhibitions(Long artistId, int startAt,
            int maxElements) {
        List<Exhibition> result = entityManager.createNamedQuery(
                "Exhibition.findByArtistId").setParameter("artistId", artistId).setFirstResult(
                startAt).setMaxResults(maxElements).getResultList();
        loadExhibitionsDependencies(result);
        return result;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Exhibition updateExhibition(Exhibition exhibition)
            throws ValidationException {
        validator.validate(exhibition);
        exhibition = entityManager.merge(exhibition);
        entityManager.flush();
        return exhibition;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public ExhibitionPhoto updatePhotoDescription(String photoKey,
            String description) {
        ExhibitionPhoto photo = entityManager.find(ExhibitionPhoto.class,
                photoKey);
        photo.setDescription(new Text(description));
        entityManager.flush();
        return photo;
    }

    private void loadExhibitionsDependencies(List<Exhibition> result) {
        for (Exhibition exhibition : result) {
            loadExhibitionDependencies(exhibition);
        }
    }

    @SuppressWarnings({ "unused" })
    private void loadExhibitionDependencies(Exhibition exhibition) {
        Address address = exhibition.getGalleryAddress();
        for (String artist : exhibition.getExhibitingArtists()) {
        }
        for (ExhibitionArtwork pa : exhibition.getArtworks()) {
        }
        for (ExhibitionPhoto photo : exhibition.getPhotos()) {
        }
        if (exhibition.getVideos() != null) {
            for (ExhibitionVideo video : exhibition.getVideos()) {
            }
        }
    }
}
